/**
 * Frame.java
 * 
 * Holds a score for the balls rolled. Frames typically will keep score for two
 * balls, but the last frame keeps the score for three balls.
 * 
 * @author Anthony Reese
 * @author Robert Yates
 * @author Ryan Walters
 */
public class Frame {

	/**
	 * The number of the frame (between 1 and 10)
	 */
	private int frameNumber;

	/**
	 * Responsible for calculating the score
	 */
	private ScoreHandler scoreHandler;

	/**
	 * The number of pins left standing after a roll
	 */
	private int pinsLeft;

	/**
	 * Used to determine if a spare or strike was rolled
	 */
	private boolean hasMissedLastBall;

	/**
	 * Creates a new Frame with a frame number
	 */
	public Frame(int frameNumber) {
		this.frameNumber = frameNumber;
		hasMissedLastBall = false;
		pinsLeft = Pinsetter.MAX_PINS;
	}

	/**
	 * Set the value for the ball rolled
	 * 
	 * @param numPins
	 *            the number of pins that fell
	 * 
	 * @return the score handler used to calculate the score
	 */
	public ScoreHandler rollBall(int numPins) {
		ScoreHandler currentScoreHandler = null;
		pinsLeft -= numPins;
		if (pinsLeft == 0) {
			if (numPins == Pinsetter.MAX_PINS && !hasMissedLastBall) {
				// rolled a strike
				currentScoreHandler = new Strike(numPins);
			} else {
				// rolled a spare
				currentScoreHandler = new Spare(numPins);
			}
			pinsLeft = 10;
		} else {
			// rolled a plain number
			currentScoreHandler = new Number(numPins);
		}

		if (scoreHandler == null) {
			scoreHandler = currentScoreHandler;
		} else {
			scoreHandler.setLastHandler(currentScoreHandler);
		}

		// Determine if the ball missed all the pins
		hasMissedLastBall = (numPins == 0);

		return scoreHandler;
	}

	/**
	 * Set the next frame that comes after this one
	 * 
	 * @param nextFrame
	 *            the frame that comes after this one
	 */
	public void linkNextFrame(Frame nextFrame) {
		scoreHandler.setLastHandler(nextFrame.scoreHandler);
	}

	/**
	 * Get the score of the frame
	 * 
	 * @return the score for this frame
	 */
	public int getScore() {
		int score = 0;
		if (scoreHandler != null) {
			boolean isLastFrame = (frameNumber == Scoreboard.MAX_FRAMES - 1);
			score = scoreHandler.getFrameScore(isLastFrame);
		}
		return score;
	}
}
